1 About

1.2 Citation

If you wish to refer to any of the material from this report please cite as:

  • Anderson, B., (2020) Air Quality in Southampton (UK): Exploring the effect of UK covid 19 lockdown on air quality , Sustainable Energy Research Group, University of Southampton: Southampton, UK.

Report circulation:

  • Public

This work is (c) 2020 the University of Southampton.

1.3 Disclaimer

I usually do energy demand research but in the absence of access to real time demand data on lockdown (unlike during the World Cup) I’m looking at other things.

2 Introduction

Data for Southampton downloaded from :

Southampton City Council collects various forms of air quality data at the sites shown in 2.1. Some of these sites feed data to AURN. The AURN data then undergoes a manual check and ratification process.

WHO publishes information on the health consequences and “acceptable” exposure levels for each of these.

Data health warning

The southampton.my-air.uk data used is not cleaned or tested for measurement error. The AURN from https://uk-air.defra.gov.uk/ has been ratified if it is more than 6 months old.

For much more detailed analysis see a longer and very messy data report.

sotonAirDT <- sotonAirDT[obsDate > as.Date("2019-01-01")]  # for speed
sotonAirDT[, `:=`(obsDate, lubridate::date(dateTimeUTC))]
sotonAirDT[, `:=`(site, ifelse(site == "Southampton A33", "Southampton A33 AURN data", site))]
sotonAirDT[, `:=`(site, ifelse(site == "Southampton Centre", "Southampton Centre AURN data", site))]
t <- sotonAirDT[!is.na(value), .(from = min(dateTimeUTC), to = max(dateTimeUTC), nObs = .N, nPollutants = uniqueN(pollutant)), 
    keyby = .(site, source)]

kableExtra::kable(t, caption = "Dates where data != NA by site and measure", digits = 2) %>% kable_styling()
Table 2.1: Dates where data != NA by site and measure
site source from to nObs nPollutants
Southampton - A33 Roadside (near docks, AURN site) southampton.my-air.uk 2019-01-02 2020-04-03 07:00:00 20003 2
Southampton - Background (near city centre, AURN site) southampton.my-air.uk 2019-01-02 2020-04-03 07:00:00 50767 5
Southampton - Onslow Road (near RSH) southampton.my-air.uk 2019-01-02 2020-03-31 09:00:00 20353 2
Southampton - Victoria Road (Woolston) southampton.my-air.uk 2019-01-02 2020-04-01 06:00:00 13022 2
Southampton A33 AURN data AURN 2020-01-01 2020-04-02 23:00:00 15189 8
Southampton Centre AURN data AURN 2020-01-01 2020-04-02 23:00:00 19720 9

3 Nitrogen Dioxide (no2)

yLab <- "Nitrogen Dioxide (ug/m3)"
no2dt <- sotonAirDT[pollutant == "no2"]

Figure 3.1 shows the most recent hourly data.

recentDT <- no2dt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$gamCap, myParams$lockdownCap, myParams$weekendCap))

# final plot - adds annotations
yMin <- min(recentDT$value)
yMax <- max(recentDT$value)

p <- addLockdownDateTime(p)
addWeekendsDateTime(p)
Nitrogen Dioxide levels, Southampton (hourly, recent)

Figure 3.1: Nitrogen Dioxide levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

4 Oxides of Nitrogen (nox)

yLab <- "Oxides of Nitrogen (ug/m3)"
noxdt <- sotonAirDT[pollutant == "nox"]

Figure 4.1 shows the most recent hourly data.

recentDT <- noxdt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$gamCap, myParams$lockdownCap, myParams$weekendCap))

# final plot - adds annotations
yMin <- min(recentDT$value)
yMax <- max(recentDT$value)

p <- addLockdownDateTime(p)

addWeekendsDateTime(p)
Oxides of nitrogen levels, Southampton (hourly, recent)

Figure 4.1: Oxides of nitrogen levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

5 Sulphour Dioxide

yLab <- "Sulphour Dioxide (ug/m3)"
so2dt <- sotonAirDT[pollutant == "so2"]

Figure 5.1 shows the most recent hourly data.

recentDT <- so2dt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$gamCap, myParams$lockdownCap, myParams$weekendCap))

yMax <- max(recentDT$value)
yMin <- min(recentDT$value)
p <- addLockdownDateTime(p)
addWeekendsDateTime(p)
Sulphour Dioxide levels, Southampton (hourly, recent)

Figure 5.1: Sulphour Dioxide levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

6 Ozone

yLab <- "Ozone (ug/m3)"
o3dt <- sotonAirDT[pollutant == "o3"]

Figure 6.1 shows the most recent hourly data.

recentDT <- o3dt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$gamCap, myParams$lockdownCap, myParams$weekendCap))

yMax <- max(recentDT$value)
yMin <- min(recentDT$value)
p <- addLockdownDateTime(p)
addWeekendsDateTime(p)
03 levels, Southampton (hourly, recent)

Figure 6.1: 03 levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

7 PM 10

yLab <- "PM 10 (ug/m3)"
pm10dt <- sotonAirDT[pollutant == "pm10"]

Figure 7.1 shows the most recent hourly data.

recentDT <- pm10dt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$lockdownCap, myParams$weekendCap))

yMax <- max(recentDT$value)
yMin <- min(recentDT$value)
p <- addLockdownDateTime(p)
addWeekendsDateTime(p)
PM10 levels, Southampton (hourly, recent)

Figure 7.1: PM10 levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

8 PM 2.5

yLab <- "PM 2.5 (ug/m3)"
pm25dt <- sotonAirDT[pollutant == "pm2.5"]

Figure 8.1 shows the most recent hourly data.

recentDT <- pm25dt[!is.na(value) & obsDate > myParams$recentCutDate]
p <- makeDotPlot(recentDT, xVar = "dateTimeUTC", yVar = "value", byVar = "site", yLab = yLab)

p <- p + scale_x_datetime(date_breaks = "2 day", date_labels = "%a %d %b") + theme(axis.text.x = element_text(angle = 90, 
    hjust = 1)) + labs(caption = paste0(myParams$gamCap, myParams$weekendCap, "\nNB: There is no WHO PM2.5 hourly threshold"))

yMax <- max(recentDT$value)
yMin <- min(recentDT$value)
p <- addLockdownDateTime(p)
addWeekendsDateTime(p)
PM2.5 levels, Southampton (hourly, recent)

Figure 8.1: PM2.5 levels, Southampton (hourly, recent)

Beware seasonal trends and weather effects

9 Annex

9.1 Missing data

Several of these datasets suffer from missing data. This is visualised below.

# dt,xvar, yvar,fillVar, yLab
p <- makeTilePlot(no2dt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Nitrogen Dioxide data availability and levels over time

Figure 9.1: Nitrogen Dioxide data availability and levels over time

# dt,xvar, yvar,fillVar, yLab
p <- makeTilePlot(noxdt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Oxides of nitrogen data availability and levels over time

Figure 9.2: Oxides of nitrogen data availability and levels over time

# dt,xvar, yvar,fillVar, yLab
p <- makeTilePlot(so2dt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Sulphour Dioxide data availability and levels over time

Figure 9.3: Sulphour Dioxide data availability and levels over time

p <- makeTilePlot(o3dt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Availability and level of o3 data over time

Figure 9.4: Availability and level of o3 data over time

p <- makeTilePlot(pm10dt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Availability and level of PM 10 data over time

Figure 9.5: Availability and level of PM 10 data over time

p <- makeTilePlot(pm25dt, xVar = "dateTimeUTC", yVar = "site", fillVar = "value", yLab = yLab)

p
Availability and level of PM 10 data over time

Figure 9.6: Availability and level of PM 10 data over time

10 Runtime

Report generated using knitr in RStudio with R version 3.6.3 (2020-02-29) running on x86_64-apple-darwin15.6.0 (Darwin Kernel Version 19.4.0: Wed Mar 4 22:28:40 PST 2020; root:xnu-6153.101.6~15/RELEASE_X86_64).

t <- proc.time() - myParams$startTime

elapsed <- t[[3]]

Analysis completed in 35.371 seconds ( 0.59 minutes).

R packages used:

  • data.table - (Dowle et al. 2015)
  • ggplot2 - (Wickham 2009)
  • here - (Müller 2017)
  • kableExtra - (Zhu 2018)
  • lubridate - (Grolemund and Wickham 2011)
  • skimr - (Arino de la Rubia et al. 2017)
  • viridis - (Garnier 2018)

References

Arino de la Rubia, Eduardo, Hao Zhu, Shannon Ellis, Elin Waring, and Michael Quinn. 2017. Skimr: Skimr. https://github.com/ropenscilabs/skimr.

Dowle, M, A Srinivasan, T Short, S Lianoglou with contributions from R Saporta, and E Antonyan. 2015. Data.table: Extension of Data.frame. https://CRAN.R-project.org/package=data.table.

Garnier, Simon. 2018. Viridis: Default Color Maps from ’Matplotlib’. https://CRAN.R-project.org/package=viridis.

Grolemund, Garrett, and Hadley Wickham. 2011. “Dates and Times Made Easy with lubridate.” Journal of Statistical Software 40 (3): 1–25. http://www.jstatsoft.org/v40/i03/.

Müller, Kirill. 2017. Here: A Simpler Way to Find Your Files. https://CRAN.R-project.org/package=here.

Wickham, Hadley. 2009. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. http://ggplot2.org.

Zhu, Hao. 2018. KableExtra: Construct Complex Table with ’Kable’ and Pipe Syntax. https://CRAN.R-project.org/package=kableExtra.